﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace RFBR.Core.Infrastructure.Models.Structure
{
    internal class KnowledgeBase : IKnowledgeBase
    {
        #region [Private Members]
        KnowledgeBaseDataType _dataType;
        #endregion

        #region [Constructors]
        public KnowledgeBase(string name = "Knowledge Base")
        {
            _dataType = KnowledgeBaseDataType.XML;
            Name = name;
            Frames = new List<IFrame>();
        }
        #endregion

        #region [Public Members]
        public string Name { get; set; }
        public KnowledgeBaseDataType DataType
        {
            get
            {
                return _dataType;
            }
        }
        public IEnumerable<IFrame> Frames { get; set; }
        public IEnumerable<IFrame> RootFrames
        {
            get
            {
                return Frames.Where(f => f.Parent == null);
            }
        }
        #endregion

        #region [Public Methods]
        public IFrame CreateFrame(string name = "Frame", IFrame parent = null, bool isSubFrame = false)
        {
            IFrame frame = new Frame(null, name);
            frame.Parent = parent;
            frame.IsSubFrame = isSubFrame;
            ((List<IFrame>)Frames).Add(frame);
            return frame;
        }

        public IFrame CreateFrame(Guid? parent = null, string name = "Frame", bool isSubFrame = false)
        {
            return CreateFrame(name, parent.HasValue ? GetFrameById(parent.Value) : null, isSubFrame);
        }

        public IFrame SetFrame(Guid id, string name = "Frame", IFrame parent = null, bool isSubFrame = false)
        {
            IFrame frame = Frames.FirstOrDefault(f => f.Id == id);
            if (frame == null)
            {
                frame = new Frame(id, name);
                ((List<IFrame>)Frames).Add(frame);
            }
            else
            {
                frame.Name = name;
            }
            frame.Parent = parent;
            frame.IsSubFrame = isSubFrame;
            return frame;
        }

        public IFrame GetFrameById(Guid id)
        {
            return Frames.FirstOrDefault(f => f.Id == id);
        }

        public ICustomObject CreateCustomObject(Guid id, string name = "Custom object", object value = null)
        {
            return new CustomObject(id, name, value);
        }

        public IVariable CreateVariable(string name = null)
        {
            return new Variable(name);
        }

        public dynamic ToJSON()
        {
            return new
            {
                Name,
                Nodes = RootFrames.Select(el => new
                {
                    el.Id,
                    el.Name,
                    Childs = GetChilds(el)
                })
            };
        }
        #endregion

        #region [Private Methods]
        private dynamic GetChilds(IFrame frame)
        {
            return frame.Childs.Select(el => new
            {
                el.Id,
                el.Name,
                Childs = GetChilds(el)
            });
        }
        #endregion
    }
}